#lang racket

;; By Spencer Hale

(require "Output.scm")

(provide setpos true? rowHasPoss? colHasPoss? settaken)

;sets the value of the matrix square to the specified value
(define setpos
  (lambda (matrix possvec pos1 pos2 val)
    (vector-set! (vector-ref matrix pos1) pos2 val)
    (vector-fill! (vector-ref (vector-ref possvec pos1) pos2) #f)
    (if (settaken possvec val pos1 pos2) #t ;(and (writeMatrix matrix) (writePossibilityMatrix possvec))
       void)))

(define true?
  (lambda (val)
    (if val #t
        #f)))

(define rowHasPoss? ; returns a function to be applied by "vector-count", to test whether each position in the row has the given value as a possibility
  (lambda (val)
    (lambda (vector)
      (vector-ref vector (- val 1)))))

(define colHasPoss? ; returns a function to be used in vector-count, checking a position in the column to see if the given value is set as possible
  (compose (lambda (val col)
             (lambda (vector)
               (if (true? (vector-ref (vector-ref vector col) (- val 1))) #t
                   #f)))))

;given a value n and position coordinates, sets corresponding possibility value for column, row, and block, to false
(define settaken
  (lambda (possvec n pos1 pos2)
    (if (equal? n 0) #t
        (if (setcoltaken possvec n pos2 0)
            (if (setrowtaken possvec n pos1 0)
                (if (setblocktaken possvec n (* 3 (quotient pos1 3)) (* 3 (quotient pos2 3)) 0 0) #t
                    #f)
                #f)
            #f))))

;sets all possibility values for n in a column determined by pos2 to false
(define setcoltaken
  (lambda (possvec n pos2 num1)
    (vector-set! (vector-ref (vector-ref possvec num1) pos2) (- n 1) #f)
    (if (equal? num1 8) #t
        (setcoltaken possvec n pos2 (+ num1 1)))))

;sets all possibility values for n in a row determined by pos1 to false
(define setrowtaken
  (lambda (possvec n pos1 num1)
    (vector-set! (vector-ref (vector-ref possvec pos1) num1) (- n 1) #f)
    (if (equal? num1 8) #t
        (setrowtaken possvec n pos1 (+ num1 1)))))

;sets all possibilitiy values for n in a block determined by pos1 and pos2 to false
(define setblocktaken
  (lambda (possvec n pos1 pos2 num1 num2)
    (vector-set! (vector-ref (vector-ref possvec (+ pos1 num1)) (+ pos2 num2)) (- n 1) #f)
    (if (and (equal? num1 2) (equal? num2 2)) #t
        (if (equal? num1 2)
            (setblocktaken possvec n pos1 pos2 num1 (+ num2 1))
            (if (equal? num2 2)
                (setblocktaken possvec n pos1 pos2 (+ num1 1) num2)
                (and (setblocktaken possvec n pos1 pos2 num1 (+ num2 1)) (setblocktaken possvec n pos1 pos2 (+ num1 1) num2)))))))
